// 服务实例
package chess

import (
	"kugo/chess/proto"
	"kugo/log"
	"kugo/utils"
	"kugo/ws"
	"strconv"
)

type serverUsercase struct{}

// 服务实例
var ServerUsercase *serverUsercase = &serverUsercase{}
var userWSCache map[string]*ws.SocketSingleton = make(map[string]*ws.SocketSingleton)

func (su *serverUsercase) Start() {
	ServerModel.Init()
	su.registerEvent()
	err := ws.StartWSServer(1234, ServerUsercase)
	if err != nil {
		log.ErrLog("error %s", err.Error())
	} else {
		log.Info("服务启动成功")
	}
}
func (su *serverUsercase) registerEvent() {
	ws.RegisterWSEvent(proto.WSCmd_Login, su.CmdLogin)
	ws.RegisterWSEvent(proto.WSCmd_JoinRoom, su.CmdJoinRoom)
	ws.RegisterWSEvent(proto.WSCmd_UserReady, su.CmdUserReady)
	ws.RegisterWSEvent(proto.WSCmd_DropChess, su.CmdDropChess)
	ws.RegisterWSEvent(proto.WSCmd_DropChessSelectKill, su.CmdKillPieces)
}

func (su *serverUsercase) ConnSuccess(socket *ws.SocketSingleton, data interface{}) {
	log.Info("连接成功")
	var userId = strconv.Itoa(int(data.(int64)))
	userWSCache[userId] = socket
}

func (su *serverUsercase) CloseSocket(socket *ws.SocketSingleton, data interface{}) {
	log.Info("关闭连接")
	var userId = strconv.Itoa(int(data.(int64)))
	delete(userWSCache, userId)
}

func (su *serverUsercase) CmdLogin(event ...interface{}) {
	ws := event[0].(*ws.SocketSingleton)
	uid := ws.GetBind().(int64)
	data := &proto.LoginRequest{}
	utils.StringToStruct(event[1], data)
	log.Info("用户登录【 %d 】data: %s", uid, utils.Struct2JSON(data))

	userData := ServerModel.AddUser(data.WXCode, data.HeadUrl, data.NickName)
	if userData == nil {
		ws.SendData(proto.WSCmd_ErrorMsg, "桌子已满")
		return
	}
	loginRet := &proto.LoginReply{}
	loginRet.User = *userData
	loginRet.RoomId = ServerModel.RoomId
	loginRet.GridSize = ServerModel.GridSize
	loginRet.RoomList = []proto.RoomInfo{}
	loginRet.Token = ""
	ws.SendData(proto.WSCmd_Login, loginRet)
}

func (su *serverUsercase) CmdJoinRoom(event ...interface{}) {
	ws := event[0].(*ws.SocketSingleton)
	uid := ws.GetBind().(int64)
	userId := strconv.Itoa(int(uid))
	data := &proto.JoinRoomRequest{}
	utils.StringToStruct(event[1], data)
	log.Info("进入房间【 %d 】data: %s", uid, utils.Struct2JSON(data))
	userInfo := ServerModel.JoinRoom(userId, data.RoomId)
	if userInfo == nil {
		ws.SendData(proto.WSCmd_ErrorMsg, "进入房间失败")
		return
	}
	joinRet := &proto.JoinRoomReply{}
	joinRet.UserList = ServerModel.Users
	su.RoomBroadcast(proto.WSCmd_JoinRoom, joinRet)

	if ServerModel.readyCount() == PLAYER_MAX {
		su.SendGameStart()
	}
}

// 房间内广播
func (su *serverUsercase) RoomBroadcast(cmd string, data interface{}) {
	for i := 0; i < len(ServerModel.Users); i++ {
		tmpUID := ServerModel.Users[i].Data.UserId
		ws := userWSCache[tmpUID]
		ws.SendData(cmd, data)
	}
}

func (su *serverUsercase) CmdUserReady(event ...interface{}) {
	ws := event[0].(*ws.SocketSingleton)
	uid := ws.GetBind().(int64)
	userId := strconv.Itoa(int(uid))
	data := &proto.UserReadyReply{}
	utils.StringToStruct(event[1], data)
	log.Info("用户准备【 %d 】data: %s", uid, utils.Struct2JSON(data))
	ret := ServerModel.UserReady(userId)
	readyRet := &proto.UserReadyReply{}
	readyRet.SeatId = ServerModel.GetUserInfoById(userId).SeatId
	readyRet.State = ServerModel.GetUserInfoById(userId).ReadyState
	su.RoomBroadcast(proto.WSCmd_UserReady, readyRet)
	if ret {
		su.SendGameStart()
	}
}

func (su *serverUsercase) SendGameStart() {
	// ServerModel.resetChessPieces()
	ServerModel.setTestData()
	gameStart := &proto.GameStartReply{}
	gameStart.ChessData = ServerModel.ChessData
	gameStart.CurOptUser = ServerModel.CurSeatId
	gameStart.State = ServerModel.CurGameState
	gameStart.Users = ServerModel.Users
	su.RoomBroadcast(proto.WSCmd_GameStart, gameStart)
}

func (su *serverUsercase) CmdKillPieces(event ...interface{}) {
	ws := event[0].(*ws.SocketSingleton)
	uid := ws.GetBind().(int64)
	userId := strconv.Itoa(int(uid))
	data := &proto.KillRequest{}
	userInfo := ServerModel.GetUserInfoById(userId)
	daLianCount := ServerControl.CheckDaLianKill(data.Point)
	if daLianCount == len(data.KillPoint) {
		ret := ServerControl.DaLianKill(data.KillPoint, userInfo.PiecesType)
		if !ret {
			ws.SendData(proto.WSCmd_ErrorMsg, "褡裢吃子失败")
		} else {
			dropRet := &proto.DropChessReply{}
			dropRet.ChessData = ServerModel.ChessData
			dropRet.CurOptUser = ServerModel.CurSeatId
			dropRet.Point = data.Point
			dropRet.CanKillCount = 0
			ServerModel.ChangeOptUser(userId)

			dropRet.NextOptUser = ServerModel.CurSeatId
			dropRet.KillPoint = data.KillPoint
			gameOver, winType := ServerControl.CheckGameEnd()
			dropRet.State = ServerModel.CurGameState
			su.RoomBroadcast(proto.WSCmd_DropChess, dropRet)

			if gameOver {
				gameResult := &proto.GameResultReply{}
				gameResult.LoseScore = 0
				gameResult.WinScore = 0
				gameResult.WinPiecesType = winType
				su.RoomBroadcast(proto.WSCmd_GameResult, gameResult)
			}
		}
	} else {
		ws.SendData(proto.WSCmd_ErrorMsg, "褡裢吃子失败")
	}
}

func (su *serverUsercase) CmdDropChess(event ...interface{}) {
	ws := event[0].(*ws.SocketSingleton)
	uid := ws.GetBind().(int64)
	userId := strconv.Itoa(int(uid))
	data := &proto.DropChessRequest{}
	utils.StringToStruct(event[1], data)
	log.Info("用户落子【 %d 】data: %s", uid, utils.Struct2JSON(data))

	userInfo := ServerModel.GetUserInfoById(userId)
	piecesType := userInfo.PiecesType

	ret, killPoint := ServerControl.DropPieces(data.Point, piecesType)
	if !ret {
		ws.SendData(proto.WSCmd_ErrorMsg, "落子失败")
		return
	}
	dropRet := &proto.DropChessReply{}
	dropRet.CurOptUser = userInfo.SeatId
	if killPoint != nil {
		dropRet.KillPoint = []proto.ChessPoint{}
		for i := 0; i < len(killPoint); i++ {
			dropRet.KillPoint = append(dropRet.KillPoint, proto.ChessPoint{
				Row: killPoint[i].Row,
				Col: killPoint[i].Col,
			})
		}
	}
	dropRet.Point = data.Point

	if ServerModel.CurGameState == GameState_DROP_PIECES {
		whiteCount, blackCount := ServerControl.ChessPiecesCount()
		if whiteCount+blackCount == ServerModel.GridSize*ServerModel.GridSize {
			ServerModel.CurGameState = GameState_JUMP
			for _, p := range ServerModel.CenterPoint {
				ServerModel.ChessData[p.Row][p.Col] = ChessPieces_NONE
			}
		}
	}

	dropRet.ChessData = ServerModel.ChessData
	gameOver, winType := ServerControl.CheckGameEnd()

	dropRet.State = ServerModel.CurGameState
	dropRet.CanKillCount = ServerControl.CheckDaLianKill(data.Point)
	if dropRet.CanKillCount == 0 {
		ServerModel.ChangeOptUser(userId)
	}
	dropRet.NextOptUser = ServerModel.CurSeatId
	su.RoomBroadcast(proto.WSCmd_DropChess, dropRet)

	if gameOver {
		gameResult := &proto.GameResultReply{}
		gameResult.LoseScore = 0
		gameResult.WinScore = 0
		gameResult.WinPiecesType = winType
		su.RoomBroadcast(proto.WSCmd_GameResult, gameResult)
	}
}
